package cn.xiaoke.fanxin.fanshe;


import cn.xiaoke.util.SsistBeanUtil;
import cn.xiaoke.fanxin.auto_wrapper.AutoWhereUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.NotFoundException;
import org.apache.ibatis.javassist.bytecode.AttributeInfo;
import org.apache.ibatis.javassist.bytecode.CodeAttribute;
import org.apache.ibatis.javassist.bytecode.LocalVariableTypeAttribute;

import java.lang.invoke.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xiaokedamowang
 * @since 2021-12-24
 */
public class MyServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements MyService<T> {
    private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
    Class<T> entityClass;
    Supplier<T> supplier;

    private Supplier<T> createLambda(Class<T> clazz){
        try {
            final MethodHandle methodHandle = lookup.unreflectConstructor(clazz.getConstructor());
            //动态调用点
            final CallSite getCallSite = LambdaMetafactory.metafactory(
                    lookup
                    , "get"
                    , MethodType.methodType(Supplier.class)
                    , MethodType.methodType(Object.class)
                    , methodHandle
                    , MethodType.methodType(entityClass)
            );
            return  (Supplier<T>)getCallSite.getTarget().invokeExact();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;
    }

    public MyServiceImpl() {
        final Class<?> aClass = this.getClass();
        final Type genericSuperclass = aClass.getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType) {
            final ParameterizedType type = (ParameterizedType) genericSuperclass;
            final Type argument = type.getActualTypeArguments()[1];
            entityClass = (Class<T>) argument;
            supplier = createLambda(entityClass);
        }
    }

    public <E> List<E> listVO(Object whereDto,Class<E> eClass) {
        try {
            final LambdaQueryWrapper<T> queryWrapper = AutoWhereUtil.lambdaQueryByAnnotation(entityClass, whereDto);
            final List<T> list = this.list(queryWrapper);
            final List<E> retList = new ArrayList<>();
            for (T t : list) {
                final E converter = SsistBeanUtil.converter(t, eClass);
                retList.add(converter);
            }
            return retList;
        } catch (Exception instantiationException) {
            instantiationException.printStackTrace();
        }
        return null;
    }

    private T createEntity() {
        return supplier.get();
    }

    @Override
    public void saveByDto(Object object) {
        final T t = createEntity();
        final T converter = SsistBeanUtil.converter(object, entityClass);
//        BeanUtil.copyProperties(object, t);
//        this.save(t);
        System.out.println(t);
    }

    public void updateByDto(Object object) {
        T t = null;
        this.updateById(t);
    }




    public static void main(String[] args) throws NoSuchMethodException, NotFoundException {
        final A<String> aa = new A<>();
        final String tt = aa.getT();

        final String className = MyServiceImpl.class.getName();
        final org.apache.ibatis.javassist.bytecode.MethodInfo main1 = ClassPool.getDefault().get(className)
                .getMethod("main", "([Ljava/lang/String;)V")
                .getMethodInfo2();
        final CodeAttribute code = main1.getCodeAttribute();
        final AttributeInfo localVariableTypeTable1 = code.getAttribute("LocalVariableTypeTable");
        final LocalVariableTypeAttribute localVariableTypeTable = (LocalVariableTypeAttribute) localVariableTypeTable1;
        System.out.println(localVariableTypeTable.descriptor(0));
        System.out.println(localVariableTypeTable.variableName(0));
        System.out.println(localVariableTypeTable.signature(0));
    }

    static class A<T> {
        T getT() {
            return null;
        }
    }
}

interface MyService<T> extends IService<T> {
    void saveByDto(Object object);

    void updateByDto(Object object);

    <E> List<E> listVO(Object whereDto,Class<E> eClass);
}



